using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using FoundationLib.Ifc.Rules;
using System.Linq.Expressions;
using System.Text.RegularExpressions;


namespace FoundationLib.Ifc.Rules 
{
	/// <summary>
	/// Abstract class representing a generic business rule for a type of entity
	/// </summary>
	public abstract class GenericRuleBase<T> : RuleBase 
	{
		private const string REGEX = @"^[^\.]+\.([^\(\)]+)$";

		/// <summary>
		/// Creates a new entity-specific business rule
		/// </summary>
		protected GenericRuleBase()
			: base(0, String.Format("Invalid{0}", typeof(T).Name), typeof(T).Name)
		{
		}

		/// <summary>
		/// Creates a new entity-specific business rule
		/// </summary>
		/// <param name="id"></param>
		/// <param name="messageResourceName"></param>
		protected GenericRuleBase(int id, string messageResourceName)
			: base(id, messageResourceName)
		{
		}

		/// <summary>
		/// Creates a new entity-specific business rule
		/// </summary>
		/// <param name="id"></param>
		/// <param name="messageResourceName"></param>
		/// <param name="category"></param>
		protected GenericRuleBase(int id, string messageResourceName, string category)
			: base(id, messageResourceName, category)
		{
		}

		/// <summary>
		/// Creates a new entity-specific business rule
		/// </summary>
		/// <param name="id">The business rule identifier</param>
		protected GenericRuleBase(int id)
			: this(id, String.Format("Invalid{0}", typeof(T).Name))
		{
		}

		private string GetPropertyName<TProperty>(Expression<Func<T, TProperty>> property)
		{
			if (property == null)
				throw new ArgumentNullException("property");
			
			Match match = Regex.Match(property.ToString(), REGEX);
			return (match.Groups.Count >= 1 ? match.Groups[1].Value : null);
		}

		/// <summary>
		/// Adds a property involved in this business rule
		/// </summary>
		/// <param name="property">The property involved</param>
		public void AddLogicalFieldInvolved<TProperty>(Expression<Func<T, TProperty>> property)
		{
			string propertyName = this.GetPropertyName(property);
			if (propertyName != null)
				this.AddLogicalFieldInvolved(propertyName);
		}

		/// <summary>
		/// Removes a property involved in this business rule
		/// </summary>
		/// <returns>True if the property was successfully removed, false else</returns>
		/// <param name="property">The property to be removed</param>
		public bool RemoveLogicalFieldInvolved<TProperty>(Expression<Func<T, TProperty>> property)
		{
			string propertyName = this.GetPropertyName(property);
			if (propertyName != null)
				return this.RemoveLogicalFieldInvolved(propertyName);
			else
				return false;
		}

	}

}